﻿using System;
using System.Windows;
using System.Windows.Media;
using WickedFlame.Core.State;
using System.Windows.Media.Imaging;

namespace WickedFlame.Core.Shapes
{
    public class TextShape : VectorShape, IStateCapturable, ICopyable
    {
        FormattedText formattedText;

        public TextShape()
            : this(new Point(0, 0))
        {
        }

        public TextShape(Point point)
        {
            Point = point;
        }

		#region Properties

		bool _isInEditMode = true;
        public bool IsInEditMode
        {
            get
            {
                return _isInEditMode;
            }
            set
            {
                _isInEditMode = value;
                Invalidate();
				NotifyPropertyChanged("IsInEditMode");
            }
        }

        string _text = "";
        public string Text
        {
            get
            {
                return _text;
            }
            set
            {
                _text = value;
                Invalidate();
            }
        }

        Point _point;
        public Point Point
        {
            get
            {
                return _point;
            }
            set
            {
                _point = value;
                Invalidate();
				NotifyPropertyChanged("Point");
            }
        }

        double _fontSize = 12;
        public double FontSize
        {
            get
            {
                return _fontSize;
            }
            set
            {
                _fontSize = value;
                Invalidate();
            }
        }

		FontFamily _fontFamily = new FontFamily("Verdana");
		public FontFamily FontFamily
        {
            get
            {
                return _fontFamily;
            }
            set
            {
                _fontFamily = value;
                Invalidate();
            }
        }

        public double LineHeight
        {
            get
            {
                return formattedText.Baseline + formattedText.Baseline - FontSize;
            }
        }

		public override Rect Bounds
		{
			get
			{
				UpdateText();

				return new Rect(Point.X, Point.Y, formattedText.WidthIncludingTrailingWhitespace, formattedText.Height);
			}
		}

		public override int TrackerCount
		{
			get
			{
				return 1;
			}
		}

		public int X
		{
			get
			{
				return (int)Point.X;
			}
			set
			{
				_point.X = value;
				this.Invalidate();
			}
		}

		public int Y
		{
			get
			{
				return (int)Point.Y;
			}
			set
			{
				_point.Y = value;
				this.Invalidate();
			}
		}

		#endregion

		#region Implementation

		public override void Invalidate()
		{
			base.Invalidate();

			NotifyPropertyChanged("X");
			NotifyPropertyChanged("Y");
			NotifyPropertyChanged("FontFamily");
			NotifyPropertyChanged("FontSize");
			NotifyPropertyChanged("Text");

			DrawingCanvas.DrawTrackers();
		}

		private void UpdateText()
        {
            formattedText = new FormattedText(
                Text,
                System.Globalization.CultureInfo.InvariantCulture,
                FlowDirection.LeftToRight,
                new Typeface(FontFamily.ToString()),
                FontSize,
                Stroke);

            //this.Invalidate();
        }

        public override Point GetTracker(int trackerNo)
        {
            return Point;
        }

        public override int HitTestInt(Point point)
        {
            if (IsSelected)
            {
                for (int i = 1; i <= TrackerCount; i++)
                {
                    if (GetTrackerRectangle(i).Contains(point))
                        return i;
                }
            }

            if (PointInObject(point))
                return 0;

            return -1;
        }

        protected override bool PointInObject(Point point)
        {
            return new Rect(Point.X, Point.Y, formattedText.WidthIncludingTrailingWhitespace, formattedText.Height).Contains(point);
        }

        public override void MoveTracker(Point point, int trackerNo)
        {
            if (trackerNo == 1)
                Point = point;
        }

        public override void MoveTracker(int tracker, double deltaX, double deltaY)
        {
            if (tracker == 1)
                Point = new Point(Point.X + deltaX, Point.Y + deltaY);
        }

        public override void Move(double deltaX, double deltaY)
        {
            Point = new Point(Point.X + deltaX, Point.Y + deltaY);
        }

        public override bool IntersectsWith(Rect rectangle)
        {
            return new Rect(Point.X, Point.Y, formattedText.WidthIncludingTrailingWhitespace, formattedText.Height).IntersectsWith(rectangle);
        }

        public override void Draw(DrawingContext drawingContext)
        {
            UpdateText();

            if (IsInEditMode)
            {
                Rect r;
                if (Point.X - 2 >= 0)
                    r = new Rect(Point.X - 2, Point.Y, formattedText.WidthIncludingTrailingWhitespace + 4, formattedText.Height);
                else
                    r = new Rect(Point.X, Point.Y, formattedText.WidthIncludingTrailingWhitespace + 2, formattedText.Height);

                if (r.Height == 0)
                    r.Height = FontSize;

                if (formattedText.Text.EndsWith("\r"))
                    r.Height += formattedText.Baseline;

                drawingContext.DrawRectangle(
                    Brushes.White,
                    new Pen(Brushes.Blue, 1),
                    r);
            }

            drawingContext.DrawText(formattedText, Point);
        }

        public override void DrawTracker(DrawingContext drawingContext, double scale)
        {
            Pen p = new Pen(Brushes.Blue, 0.5 / scale);
            
            drawingContext.DrawRectangle(
                null, 
                p,
                new Rect(Point.X, Point.Y, formattedText.WidthIncludingTrailingWhitespace, formattedText.Height));

            double r = 2.5 / scale;

            if (!(SelectedTracker == 1))
            {
                p = new Pen(Brushes.Blue, 1 / scale);
                drawingContext.DrawEllipse(Brushes.LightBlue, p, Point, r, r);
            }
            else
            {
                p = new Pen(Brushes.Black, 2 / scale);
                drawingContext.DrawEllipse(Brushes.White, p, Point, r, r);
            }
        }

		#endregion

		#region IStateCapturable Member

		public ShapeMemento CreateMementoState()
        {
            var memento = new TextMemento();
            memento.SaveProperties(this);
            return memento;
        }

        public void ResetState(ShapeMemento memento)
        {
            memento.ResetProperties(this);
            this.Invalidate();
        }

        #endregion

        #region ICopyable Members

        public VectorShape Copy()
        {
            var shape = new TextShape(Point);
            shape.FontFamily = FontFamily;
            shape.FontSize = FontSize;
            shape.Text = Text;
            shape.Fill = this.Fill;
            shape.Stroke = this.Stroke;
            shape.StrokeThickness = this.StrokeThickness;

            return shape;
        }

        #endregion
    }
}
